/*
  Copyright 2006 by Sean Luke and George Mason University
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/

package sim.portrayal.simple;
import sim.portrayal.*;
import java.awt.*;
import sim.display.*;
import sim.util.*;

/**
   A wrapper for multiple Portrayal2Ds which calls on one or the other one according to the
   underlying state of the object, which must be Valuable or a Number of some sort.  The
   particular sub-portrayal (called a "facet") chosen is based on the integer value returned
   (or converted to an integer if it's a double).  Optionally FacetedPortrayal2D will call on
   *all* its underlying portrayals at one time.  If any array element is null, FacetedPortrayal2D
   will assume it represents the object itself (assuming the object itself is also a SimplePortrayal2D).
*/

public class FacetedPortrayal2D extends SimplePortrayal2D
    {
    public SimplePortrayal2D[] children;
    boolean portrayAllChildren = false;
    boolean errorThrown;
    
    /** If child is null, then the underlying model object 
        is presumed to be a Portrayal2D and will be used. */
    public FacetedPortrayal2D(SimplePortrayal2D[] children, boolean portrayAllChildren)
        {
        this.children = children;
        this.portrayAllChildren = portrayAllChildren;
        }
    
    /** If child is null, then the underlying model object 
        is presumed to be a Portrayal2D and will be used. */
    public FacetedPortrayal2D(SimplePortrayal2D[] children)
        {
        this(children, false);
        }
    
    /** Returns the child index to use for the given object.
        The value must be >= 0 and < numIndices.   The default implementation
        returns the value of the object if it's a Number or is sim.util.Valuable
        and if the value is within the given range (and is an integer).
        Otherwise 0 is returned.
    */
    public int getChildIndex(Object object, int numIndices)
        {
        int element = 0;
        if( object instanceof Number )
            element = (int)(((Number)object).doubleValue());
        else if (object instanceof Valuable)
            element = (int)(((Valuable)object).doubleValue());
        if (element < 0 || element >= children.length)
            {
            if (!errorThrown)
                {
                errorThrown = true;
                System.err.println("FacetedPortrayal was given a value that doesn't correspond to any array element.");
                }
            element = 0;
            }
        return element;
        }
        
    SimplePortrayal2D getChild(Object object)
        {
        int element = getChildIndex(object, children.length);
        if (children[element] == null)
            if (object instanceof SimplePortrayal2D)
                return (SimplePortrayal2D)object;
            else throw new RuntimeException("FacetedPortrayal had a null child but the object is not itself a SimplePortrayal2D");
        else return children[element];
        }
        
    public void draw(Object object, Graphics2D graphics, DrawInfo2D info)
        {
        if (portrayAllChildren)
            for(int i = 0; i < children.length;i++)
                children[i].draw(object, graphics, info);
        else
            getChild(object).draw(object, graphics, info);
        }
        
    public boolean hitObject(Object object, DrawInfo2D range)
        {
        if (portrayAllChildren)
            {
            for(int i = 0; i < children.length;i++)
                if (children[i].hitObject(object, range))
                    return true;
            return false;
            }
        else
            return getChild(object).hitObject(object,range);
        }

    /** If portrayAllChildren, Returns true if any ONE of the children returns true. */
    public boolean setSelected(LocationWrapper wrapper, boolean selected)
        {
        if (portrayAllChildren)
            {
            for(int i = 0; i < children.length;i++)
                if (children[i].setSelected(wrapper, selected))
                    return true;
            return false;
            }
        else
            return getChild(wrapper.getObject()).setSelected(wrapper, selected);
        }

    /** If portrayAllChildren, Calls on the first child to return the inspector. */
    public Inspector getInspector(LocationWrapper wrapper, GUIState state)
        {
        if (portrayAllChildren)
            return children[0].getInspector(wrapper,state);
        else
            return getChild(wrapper.getObject()).getInspector(wrapper,state);
        }
    
    /** If portrayAllChildren, Calls on the first child to return the name. */
    public String getName(LocationWrapper wrapper)
        {
        if (portrayAllChildren)
            return children[0].getName(wrapper);
        else
            return getChild(wrapper.getObject()).getName(wrapper);
        }

    }
    
    
    
